﻿using System;
using System.Xml;
using System.Xml.Schema;
using System.Xml.XPath;
using System.Collections.Generic;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;


using cz.uhul.DSMLv2;


namespace cz.uhul.DSMLv2.client
{


  //[System.Diagnostics.DebuggerStepThroughAttribute()]
  //[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "4.0.0.0")]
  public partial class LdConnection : System.ServiceModel.ClientBase<ILdConnection>, ILdConnection
  {



    public static readonly MessageVersion DSMLv2MessageVersionDefault = MessageVersion.CreateVersion(
      EnvelopeVersion.Soap11
      , AddressingVersion.None
    );



    //public static readonly MessageVersion DSMLv2MessageVersionRemote = MessageVersion.CreateVersion(
    //  EnvelopeVersion.Soap11
    //  , AddressingVersion.WSAddressing10
    //);



    public LdConnection()
    {
    }

    public LdConnection(string endpointConfigurationName) :
      base(endpointConfigurationName)
    {
    }

    public LdConnection(string endpointConfigurationName, string remoteAddress) :
      base(endpointConfigurationName, remoteAddress)
    {
    }

    public LdConnection(string endpointConfigurationName, System.ServiceModel.EndpointAddress remoteAddress) :
      base(endpointConfigurationName, remoteAddress)
    {
    }

    public LdConnection(System.ServiceModel.Channels.Binding binding, System.ServiceModel.EndpointAddress remoteAddress) :
      base(binding, remoteAddress)
    {
    }




    public MessageVersion ChannelMessageVersion { get; set; }




    /// <summary>
    /// use ProcessRequest instead, this is just interface member, not for direct use
    /// </summary>
    /// <param name="request"></param>
    /// <returns></returns>
    public Message Process(Message request)
    {
      return base.Channel.Process(request);
    }




    /// <summary>
    /// send <c>LDRequestDocument</c> with DSML message on server
    /// </summary>
    /// <param name="batchRequest">DSML batchRequest</param>
    /// <returns>server response</returns>
    public LdResponseDocument SendRequest(LdRequestDocument batchRequest)
    {

      Message tmp = Message.CreateMessage(ChannelMessageVersion, "*", batchRequest.ToXmlReader());
      Message tmpRespMsg = this.Process(tmp);

      if (tmpRespMsg.IsFault)
      {
        throw new FaultException(tmpRespMsg.ToString());
      }

      //XmlDocument outDoc = new XmlDocument();
      //XPathNavigator nav = outDoc.CreateNavigator();

      //XmlDictionaryWriter writer = XmlDictionaryWriter.CreateDictionaryWriter(nav.AppendChild());

      //tmpRespMsg.WriteBodyContents(writer);

      //writer.Close();

      return LdResponseDocument.Parse(tmpRespMsg.GetReaderAtBodyContents());
    }




    /// <summary>
    /// create connection from address
    /// with default client binding
    /// </summary>
    /// <param name="endPointAddressUri">service Uri</param>
    /// <returns>LdConnection ready for communication</returns>
    public static LdConnection CreateConnection(Uri endPointAddressUri)
    {
      if (!endPointAddressUri.IsAbsoluteUri)
        //endPointAddress = new Uri(Application.Current.Host.Source, vUrl);
        throw new NotImplementedException("please specify absolute Uri");

      LdConnection tmpConn = new LdConnection(CreateBasicHttpBinding(endPointAddressUri), new EndpointAddress(endPointAddressUri));

      tmpConn.ChannelMessageVersion = DSMLv2MessageVersionDefault;

      return tmpConn;
      //return new LdConnection(CreateBasicHttpBinding(), new EndpointAddress(endPointAddressUri));
    }






    protected static BasicHttpBinding CreateBasicHttpBinding(Uri endPointAddressUri)
    {

      BasicHttpBinding bind = new BasicHttpBinding()
      {
        AllowCookies = false
        ,ReceiveTimeout = new TimeSpan(0, 30, 0)
        ,OpenTimeout = new TimeSpan(0, 5, 0)
        ,SendTimeout = new TimeSpan(0, 5, 0)
        ,CloseTimeout = new TimeSpan(0, 5, 0)
        ,MaxBufferSize = 2000000
        ,MaxBufferPoolSize = 5342880
        ,HostNameComparisonMode = HostNameComparisonMode.StrongWildcard
        ,MessageEncoding = WSMessageEncoding.Text
        ,Namespace = ""
        ,TextEncoding = System.Text.Encoding.UTF8
        ,TransferMode = TransferMode.Buffered
        ,MaxReceivedMessageSize = 2000000
        ,BypassProxyOnLocal = false
        ,UseDefaultWebProxy = true
      };

      bind.ReaderQuotas.MaxDepth = 32;
      bind.ReaderQuotas.MaxStringContentLength = 8192;

      if (endPointAddressUri.Scheme == "https")
      {
        bind.Security.Mode = BasicHttpSecurityMode.Transport;
        bind.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
        bind.Security.Message.AlgorithmSuite = System.ServiceModel.Security.SecurityAlgorithmSuite.Default;
        bind.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
      }

      else
        bind.Security.Mode = BasicHttpSecurityMode.None;

      return bind;
    }







    protected static CustomBinding CreateCustomBinding(Uri endPointAddressUri, MessageVersion ver)
    {

      //resolve bindings...
      List<BindingElement> elements = new List<BindingElement>();

      //elements.Add(new System.ServiceModel.Configuration.BasicHttpContextBindingElement());

      elements.Add(new TextMessageEncodingBindingElement(ver, System.Text.Encoding.UTF8));

      if (endPointAddressUri.Scheme.Equals("https", StringComparison.InvariantCultureIgnoreCase))
      {
        elements.Add(new HttpsTransportBindingElement
        {
          MaxBufferSize = 2147483647,
          MaxReceivedMessageSize = 2147483647
        });
      }
      else
      {
        elements.Add(new HttpTransportBindingElement
        {
          MaxBufferSize = 2147483647,
          MaxReceivedMessageSize = 2147483647
        });
      }

      return new CustomBinding(elements);
    }




  }

}
